home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
emerald
/
emrldsys.lha
/
Language
/
Compiler
/
writeTree.c
< prev
Wrap
C/C++ Source or Header
|
1990-08-16
|
19KB
|
710 lines
/*
* @(#)writeTree.c 1.6 3/13/89
*/
#include "assert.h"
#include "error.h"
#include "scan.h"
#include "nodes.h"
#include "symbols.h"
#include "MyParser.h"
#include "semantics.h"
#include "system.h"
#include "map.h"
#include "version.h"
#include "environment.h"
#include "flags.h"
#include <a.out.h>
#include "builtins.h"
#include "trace.h"
extern char *ATName();
extern void myLink();
#define MAXRELOCATIONBLOCKS 400
#define BLOCKSIZE 1024
#define RELOCATIONSPERBLOCK (1024 / sizeof(struct relocation_info))
static char *theOIDFileName;
static int treeVersion = TREEVERSION;
static struct exec header;
static struct sts {
int size;
char strings[20];
} *stringTable;
static int stringTableSize;
static struct nlist symbolTable;
typedef struct {
struct relocation_info rl[RELOCATIONSPERBLOCK];
} RelocationBlock, *RelocationBlockPtr;
static RelocationBlockPtr relocationBlocks[MAXRELOCATIONBLOCKS];
static int nextRelocationBlockIndex;
static RelocationBlockPtr rbp;
static struct relocation_info *rp, *rpe;
static int nextOffset;
static FILE *fp;
static Map offsetMap, CTMap;
static int Pass;
static void _DoAReference(), writeInt(), Pass1(), Pass2(), writeBody();
#define OFFSETOF(fNode) Map_Lookup(offsetMap, (int) fNode)
#define SETOFFSET(fNode, value) Map_Insert(offsetMap, (int)fNode, (int)value)
static int getOffset();
static NodePtr theRoot, aGlobalRef;
/*
* When we write out the file, we write out all the tree nodes. Global
* references are changed to remove the "cache". Builtin object references
* are left alone. We then write out the modified symbol table and ident
* table entries.
*/
static void squirrelSymbol(p)
NodePtr p;
{
register Symbol st = p->b.symdef.symbol;
int filePosition, rightFilePosition;
int thisSymbolOffset;
st = ST_Fetch(st);
if (OFFSETOF(st) == NIL) {
assert(Pass == 1);
thisSymbolOffset = nextOffset;
SETOFFSET(st, thisSymbolOffset);
nextOffset += 2 + 2 + 1 + 1 + 1 + 1; /* up to value */
if ((int)st->value.ATinfo > 0x200) _DoAReference(nextOffset);
nextOffset += sizeof(NodePtr);
if ((int)st->value.CTinfo > 0x200) _DoAReference(nextOffset);
nextOffset += sizeof(NodePtr);
if ((int)st->value.value > 0x200) _DoAReference(nextOffset);
nextOffset += sizeof(NodePtr);
nextOffset += sizeof(Address);
if (st->itsName != NULL) _DoAReference(nextOffset);
nextOffset += sizeof(char *);
if (st->itsName != NULL) nextOffset += ((strlen(st->itsName)+1+3) & ~0x3);
Pass1(st->value.ATinfo, FALSE);
if ((int) st->value.CTinfo > 0x200) Map_Insert(CTMap, (int)st->value.CTinfo, 1);
Pass1(st->value.value, FALSE);
}
if (Pass == 2) {
/* write the tree node */
filePosition = ftell(fp);
rightFilePosition = getOffset(p) + sizeof(struct exec);
assert (filePosition == rightFilePosition);
writeBody(p, 1);
writeInt(getOffset((NodePtr)p->b.symdef.symbol));
/* now check for the symbol itself */
thisSymbolOffset = OFFSETOF(st);
if (thisSymbolOffset < 0) return;
SETOFFSET(st, -thisSymbolOffset);
filePosition = ftell(fp);
rightFilePosition = thisSymbolOffset + sizeof(struct exec);
assert (filePosition == rightFilePosition);
if (fwrite((char *)st, 8, 1, fp) != 1) assert(FALSE);
writeInt(getOffset(st->value.ATinfo));
writeInt(getOffset(st->value.CTinfo));
writeInt(getOffset(st->value.value ));
if (fwrite((char *)&st->v.address, sizeof(Address), 1, fp) != 1) assert(FALSE);
writeInt(thisSymbolOffset + sizeof(STEntry));
filePosition = ftell(fp);
rightFilePosition += sizeof(STEntry);
assert(filePosition == rightFilePosition);
if (st->itsName != NULL) {
register int i, strLength;
i = strlen(st->itsName);
strLength = (i+1+3) & ~0x3;
if (fwrite(st->itsName, 1, i, fp) != i) assert(FALSE);
for (; i < strLength; i++) (void) fputc('\0', fp);
}
Pass2(st->value.ATinfo, FALSE);
Pass2(st->value.value, FALSE);
}
}
/*
* This one needs to initialize the header, and initialize the mapping
* structures.
*/
static void initializeOutput(treeName)
char *treeName;
{
#ifdef sun
header.a_dynamic = 0;
header.a_machtype = M_68020;
#endif
header.a_magic = 0407;
header.a_text = 0;
header.a_bss = 0;
header.a_syms = 1 * sizeof(struct nlist);
symbolTable.n_un.n_strx = 4;
symbolTable.n_type = N_DATA;
if (*treeName == '_') symbolTable.n_type |= N_EXT;
symbolTable.n_other = 0;
symbolTable.n_desc = 0;
symbolTable.n_value = 12;
stringTableSize = (strlen(treeName) + 1 + 3) & ~0x3;
stringTableSize += 4;
stringTable = (struct sts *) calloc((unsigned)stringTableSize, 1);
stringTable->size = stringTableSize;
(void) strcpy(stringTable->strings, treeName);
header.a_entry = 0;
header.a_trsize = 0;
nextRelocationBlockIndex = 0;
rbp = (RelocationBlockPtr) calloc(sizeof (RelocationBlock), 1);
relocationBlocks[nextRelocationBlockIndex++] = rbp;
rp = &rbp->rl[0];
rpe = &rp[RELOCATIONSPERBLOCK];
nextOffset = 12;
/*
* Leaves header.a_data and header.a_drsize undone.
*/
offsetMap = Map_Create();
CTMap = Map_Create();
Pass = 1;
}
static void Pass1CTs()
{
NodePtr ct;
int value;
Map_For(CTMap, ct, value)
assert(value == 1);
if (ct->tag == P_OBLIT && ct->b.oblit.f.dependsOnTypeVariable) {
/* do nothing */
} else {
if (OFFSETOF(ct) == NIL) {
/* we have not done this one already */
Pass1(ct, TRUE);
}
}
Map_Next
}
static void Pass2CTs()
{
NodePtr ct;
int value;
Map_For(CTMap, ct, value)
assert(value == 1);
if (ct->tag == P_OBLIT && ct->b.oblit.f.dependsOnTypeVariable) {
/* do nothing */
} else {
if (OFFSETOF(ct) >= 0) {
/* we have not done this one already */
Pass2(ct, TRUE);
}
}
Map_Next
}
static void intermediate()
{
int i;
header.a_data = nextOffset;
header.a_drsize = (nextRelocationBlockIndex - 1) * BLOCKSIZE +
(int) rp - (int) rbp;
if (fwrite((char *)&header, sizeof(header), 1, fp) != 1) assert(FALSE);
/* We write the tree Version number here. We also need to make
the offsets all non zero. */
i = TREEMAGIC;
if (fwrite((char *)&i, sizeof(int), 1, fp) != 1) assert(FALSE);
if (fwrite((char *)&treeVersion, sizeof(int), 1, fp) != 1) assert(FALSE);
if (fwrite((char *)&nextOffset, sizeof(int), 1, fp) != 1) assert(FALSE);
Pass = 2;
}
static void finalize()
{
int filePosition, rightFilePosition;
register int i;
filePosition = ftell(fp);
rightFilePosition = sizeof(struct exec) + header.a_data;
assert (filePosition == rightFilePosition);
for (i = 0; i < nextRelocationBlockIndex - 1; i++) {
if (fwrite((char *)relocationBlocks[i], BLOCKSIZE, 1, fp) != 1) assert(FALSE);
free((char *)relocationBlocks[i]);
}
i = (int) rp - (int) &rbp->rl[0];
if (i != 0) if (fwrite((char *)rbp, i, 1, fp) != 1) assert(FALSE);
free((char *)rbp);
if (fwrite((char *)&symbolTable, sizeof(symbolTable), 1, fp) != 1) assert(FALSE);
if (fwrite((char *)stringTable, stringTableSize, 1, fp) != 1) assert(FALSE);
free((char *)stringTable);
Map_Destroy(offsetMap);
Map_Destroy(CTMap);
}
#define DOAREFERENCE(fNode, fE) \
if ((int) (fE) > 0x200) \
_DoAReference(thisNodeOffset + (int)(&(fE))-(int)fNode)
static void _DoAReference(offset)
int offset;
{
register struct relocation_info *myrp;
if (rp >= rpe) {
if (nextRelocationBlockIndex >= MAXRELOCATIONBLOCKS) {
fprintf(stderr, "Out of relocation blocks (allocated %d)\n",
MAXRELOCATIONBLOCKS * RELOCATIONSPERBLOCK);
exit(1);
}
rbp = (RelocationBlockPtr) calloc(sizeof (RelocationBlock), 1);
relocationBlocks[nextRelocationBlockIndex++] = rbp;
rp = &rbp->rl[0];
rpe = &rp[RELOCATIONSPERBLOCK];
}
myrp = rp++;
myrp->r_address = offset;
myrp->r_symbolnum = N_DATA;
myrp->r_pcrel = 0;
myrp->r_length = 2;
myrp->r_extern = 0;
}
static Boolean doneFirstNode;
static Boolean OBLitShouldBeSeparate(p)
NodePtr p;
{
if (p != theRoot && p->b.oblit.f.writeSeparately) return(TRUE);
if (!bflag && p->tag == P_OBLIT && p->b.oblit.f.inExecutableConstruct &&
(EnvironmentStage)Map_Lookup(environmentMap, (int)p->b.oblit.codeOID) == E_Imported)
return(TRUE);
return(FALSE);
}
static void scheduleOBLitOutput(p, id)
NodePtr p;
OID id;
{
if (bflag) {
if (((id & 0xff000000) == (OID) 0xff000000) &&
((id & 0x1f) == (theRoot->b.oblit.id & 0x1f))) {
scheduleOutput(id);
} else if ((id & 0xffffff00) != (OID)0xff000000) {
TRACE2(builtins, 1, "Writing tree for non-builtin %s with id 0x%08x", ATName(p), id);
scheduleOutput(id);
} else {
TRACE2(builtins, 1, "Not writing tree for %s with id 0x%08x", ATName(p), id);
}
} else {
scheduleOutput(id);
}
}
static void Pass1(fNode, isCT)
register NodePtr fNode;
Boolean isCT;
{
register int i;
int thisNodeOffset;
Boolean done = FALSE;
Symbol st;
NodePtr saveAT;
if ((int)fNode <= 0x200) {
/* don't worry about these. */
} else if (fNode == theRoot && doneFirstNode) {
nextOffset += UsedNodeSize(aGlobalRef);
} else if (OFFSETOF(fNode) != NIL) {
/* We've done this one already */
} else {
doneFirstNode = TRUE;
thisNodeOffset = nextOffset;
SETOFFSET(fNode, thisNodeOffset);
nextOffset += UsedNodeSize(fNode);
switch (fNode->tag) {
case P_GLOBALREF:
done = TRUE;
break;
case P_OPNAME:
done = TRUE;
break;
case P_ATLIT:
assert(!isCT);
if (OBLitShouldBeSeparate(fNode)) {
/*
* We have a pointer to a manifest atlit. We need to write out a
* globalref node.
*/
nextOffset -= UsedNodeSize(fNode);
nextOffset += UsedNodeSize(aGlobalRef);
done = TRUE;
}
break;
case P_OBLIT:
if (isCT || OBLitShouldBeSeparate(fNode)) {
/*
* We have a pointer to a manifest oblit. We need to write out a
* globalref node.
*/
nextOffset -= UsedNodeSize(fNode);
nextOffset += UsedNodeSize(aGlobalRef);
done = TRUE;
} else {
if (fNode->b.oblit.f.isTypeVariable) {
saveAT = fNode->b.oblit.myat;
fNode->b.oblit.myat = NULL;
}
st = ST_Fetch(fNode->b.oblit.name->b.symdef.symbol);
st->value.ATinfo = fNode->b.oblit.myat;
for (i = fNode->firstChild; i < fNode->nChildren; i++) {
DOAREFERENCE(fNode, fNode->b.children[i]);
Pass1(fNode->b.children[i], FALSE);
}
if (fNode->b.oblit.f.isTypeVariable) {
fNode->b.oblit.myat = saveAT;
st = ST_Fetch(fNode->b.oblit.name->b.symdef.symbol);
st->value.ATinfo = saveAT;
}
done = TRUE;
}
break;
case T_IDENT:
done = TRUE;
break;
case T_STRING:
case P_CHARLIT:
case P_INTLIT:
case P_REALLIT:
case P_STRINGLIT:
/* We write the string */
DOAREFERENCE(fNode, fNode->b.string.string);
nextOffset += ((strlen(fNode->b.string.string)+1+3) & ~0x3);
done = TRUE;
break;
case P_BOOLLIT:
done = TRUE;
break;
case P_BUILTINLIT:
done = TRUE;
break;
case P_PARAM:
case P_ARG:
break;
case P_SYMREF:
case P_SYMDEF:
DOAREFERENCE(fNode, fNode->b.symdef.symbol);
squirrelSymbol(fNode);
done = TRUE;
break;
case P_FIELDREF:
assert(FALSE);
break;
case P_OPSIG:
break;
case P_COMP:
case P_IMPORT:
assert(FALSE);
break;
case P_EXPORT:
break;
case P_RECORDLIT:
case P_UNIONLIT:
case P_ENUMLIT:
assert(FALSE);
break;
case P_CONSTDECL:
case P_VARDECL:
case P_VECTORLIT:
case P_PRAGMA:
case P_MONITOR:
case P_OPDEF:
case P_PROCESSDEF:
case P_INITDEF:
case P_RECOVERYDEF:
case P_BLOCK:
case P_UNAVAILABLEHANDLER:
case P_FAILUREHANDLER:
case P_IFSTAT:
case P_IFCLAUSE:
case P_ELSECLAUSE:
case P_LOOPSTAT:
case P_EXITSTAT:
case P_ASSIGNSTAT:
case P_ASSERTSTAT:
case P_FIXSTAT:
case P_REFIXSTAT:
case P_UNFIXSTAT:
case P_MOVESTAT:
case P_VIEW:
case P_EXP:
case P_INVOC:
break;
case P_FIELDSEL:
case P_NTHRESULT:
case P_KNOWCT:
case P_KNOWLOCAL:
case P_KNOWMANIFEST:
case P_SUBSCRIPT:
case P_SELECTION:
assert(FALSE);
break;
case P_WHEREWIDGIT:
case P_PRIMSTAT:
case P_WAITSTAT:
case P_SIGNALSTAT:
case P_UNARYEXP:
case P_RESTRICT:
case P_SETQ:
break;
default:
break;
}
if (!done) for (i = fNode->firstChild; i < fNode->nChildren; i++) {
DOAREFERENCE(fNode, fNode->b.children[i]);
Pass1(fNode->b.children[i], FALSE);
}
}
}
#define IABS(N) ((N) < 0 ? -(N) : (N))
static int getOffset(fNode)
register NodePtr fNode;
{
register int i;
if ((int) fNode <= 0x200) return ((int) fNode);
else {
i = OFFSETOF(fNode);
return (IABS(i));
}
}
static void writeInt(n)
int n;
{
if (fwrite((char *) &n, sizeof(int), 1, fp) != 1) assert(FALSE);
}
static void writeBody(fNode, n)
register NodePtr fNode;
int n;
{
if (fwrite((char *)fNode, (2+n)*sizeof(int), 1, fp) != 1) assert(FALSE);
}
static OID transOID(id)
OID id;
{
register OID result;
result = (OID) Map_Lookup(translateOIDMap, (int)id);
return (result == NIL ? id : result);
}
static void Pass2(fNode, isCT)
register NodePtr fNode;
Boolean isCT;
{
register int i;
Boolean done = FALSE;
int strLength;
int filePosition, rightFilePosition;
if ((int)fNode <= 0x200) {
/* don't worry about these. */
} else if (fNode == theRoot && doneFirstNode) {
aGlobalRef->b.globalref.id = fNode->b.atlit.id;
writeBody(aGlobalRef, 2);
} else if (OFFSETOF(fNode) < 0) {
/* We've written this one already */
} else {
doneFirstNode = TRUE;
filePosition = ftell(fp);
rightFilePosition = OFFSETOF(fNode) + sizeof(struct exec);
assert (filePosition == rightFilePosition);
SETOFFSET(fNode, -OFFSETOF(fNode));
switch (fNode->tag) {
case P_GLOBALREF:
if (bflag)
fNode->b.globalref.id = transOID(fNode->b.globalref.id);
writeBody(fNode, 1);
writeInt(0);
done = TRUE;
break;
case P_OPNAME:
writeBody(fNode, 2);
done = TRUE;
break;
case P_ATLIT:
assert(!isCT);
if (OBLitShouldBeSeparate(fNode)) {
/*
* We have a pointer to a manifest atlit. We need to write out a
* globalref node.
*/
aGlobalRef->b.globalref.id = fNode->b.atlit.id;
if (bflag)
aGlobalRef->b.globalref.id = transOID(aGlobalRef->b.globalref.id);
writeBody(aGlobalRef, 2);
if (!isCT) scheduleOBLitOutput(fNode, aGlobalRef->b.globalref.id);
done = TRUE;
}
break;
case P_OBLIT:
if (isCT || OBLitShouldBeSeparate(fNode)) {
/*
* We have a pointer to a manifest oblit. We need to write out a
* globalref node.
*/
if (isCT) {
assert(fNode->b.oblit.codeOID != 0);
aGlobalRef->b.globalref.id = fNode->b.oblit.codeOID;
} else {
aGlobalRef->b.globalref.id =
fNode->b.oblit.id ? fNode->b.oblit.id : fNode->b.oblit.codeOID;
}
if (bflag)
aGlobalRef->b.globalref.id = transOID(aGlobalRef->b.globalref.id);
writeBody(aGlobalRef, 2);
if (!isCT) scheduleOBLitOutput(fNode, aGlobalRef->b.globalref.id);
done = TRUE;
} else {
if (!bflag && fNode->b.oblit.codeOID != 0) {
char *theSecondOIDFileName;
theSecondOIDFileName = makeOIDFileName(fNode->b.oblit.codeOID);
myLink(theOIDFileName, theSecondOIDFileName, TRUE, fNode);
TRACE2(environment, 5, "Linking %s to %s", theSecondOIDFileName,
theOIDFileName);
}
}
break;
case T_IDENT:
break;
case T_STRING:
case P_CHARLIT:
case P_INTLIT:
case P_REALLIT:
case P_STRINGLIT:
/* We write the string */
writeBody(fNode, 0);
writeInt((int)(-OFFSETOF(fNode) + BODYSIZE + 4));
strLength = (strlen(fNode->b.string.string)+1+3) & ~0x3;
i = strlen(fNode->b.string.string);
if (fwrite(fNode->b.string.string, 1, i, fp) != i) assert(FALSE);
for (; i < strLength; i++) (void) fputc('\0', fp);
done = TRUE;
break;
case P_BOOLLIT:
break;
case P_BUILTINLIT:
break;
case P_PARAM:
case P_ARG:
break;
case P_SYMREF:
case P_SYMDEF:
squirrelSymbol(fNode);
done = TRUE;
break;
case P_FIELDREF:
assert(FALSE);
break;
case P_OPSIG:
break;
case P_COMP:
case P_IMPORT:
assert(FALSE);
break;
case P_EXPORT:
break;
case P_RECORDLIT:
case P_UNIONLIT:
case P_ENUMLIT:
assert(FALSE);
break;
case P_CONSTDECL:
case P_VARDECL:
case P_VECTORLIT:
case P_PRAGMA:
case P_MONITOR:
case P_OPDEF:
case P_PROCESSDEF:
case P_INITDEF:
case P_RECOVERYDEF:
case P_BLOCK:
case P_UNAVAILABLEHANDLER:
case P_FAILUREHANDLER:
case P_IFSTAT:
case P_IFCLAUSE:
case P_ELSECLAUSE:
case P_LOOPSTAT:
case P_EXITSTAT:
case P_ASSIGNSTAT:
case P_ASSERTSTAT:
case P_FIXSTAT:
case P_REFIXSTAT:
case P_UNFIXSTAT:
case P_MOVESTAT:
case P_VIEW:
case P_EXP:
case P_INVOC:
break;
case P_FIELDSEL:
case P_NTHRESULT:
case P_KNOWCT:
case P_KNOWLOCAL:
case P_KNOWMANIFEST:
case P_SUBSCRIPT:
case P_SELECTION:
assert(FALSE);
break;
case P_WHEREWIDGIT:
case P_PRIMSTAT:
case P_WAITSTAT:
case P_SIGNALSTAT:
case P_UNARYEXP:
case P_RESTRICT:
case P_SETQ:
break;
default:
break;
}
if (!done) {
writeBody(fNode, fNode->firstChild);
for (i = fNode->firstChild; i < fNode->nChildren; i++) {
writeInt(getOffset(fNode->b.children[i]));
}
for (i = fNode->firstChild; i < fNode->nChildren; i++) {
Pass2(fNode->b.children[i], FALSE);
}
}
}
}
void writeTree(fileName, p)
char *fileName;
NodePtr p;
{
char *treeName;
NodePtr symdef;
if (BODYSIZE != 8) assert(FALSE);
aGlobalRef = Construct(P_GLOBALREF, 0);
fp = fopen(fileName, "w");
theOIDFileName = fileName;
assert (fp != NULL);
p = GETVALUE(p);
symdef = p->tag == P_OBLIT ? p->b.oblit.name : p->b.atlit.name;
if (symdef == NULL) treeName = "unknown";
else treeName = ST_Fetch(symdef->b.symdef.symbol)->itsName;
if (!bflag || (p->b.oblit.id & 0xffffff) > (OID)0x000100) {
treeName = malloc(20);
sprintf(treeName, "OID%08x", p->b.oblit.id);
}
initializeOutput(treeName);
theRoot = p;
doneFirstNode = FALSE;
Pass1(p, FALSE);
Pass1CTs();
intermediate();
doneFirstNode = FALSE;
Pass2(p, FALSE); /* writes the data */
Pass2CTs();
finalize(); /* relocation and symtab */
if (fclose(fp) == EOF) assert(FALSE);
fp = NULL;
}